package com.naiterui.ehp.bs.doctor.controller;

import com.naiterui.ehp.bp.constants.SwaggerTag;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.encypt.GengerCode;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import com.naiterui.ehp.bs.doctor.service.IDoctorService;
import com.naiterui.ehp.bs.doctor.service.ILoginService;
import com.naiterui.ehp.bs.doctor.utils.PropertyValueConstants;
import com.naiterui.ehp.bs.doctor.utils.RedisUtils;
import com.naiterui.ehp.bs.doctor.utils.SMSUtil;
import com.naiterui.ehp.bs.doctor.utils.SMSUtil.Template;
import com.naiterui.ehp.bs.doctor.utils.SignatureVerifyUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

/**
 * 发送短信的接口
 *
 * @author chenlin
 */
@Api(tags = {SwaggerTag.DOCTOR + SwaggerTag.USER_ACCOUNT})
@Controller
@RequestMapping("ad")
public class AdSendSMSController {

    private static final Logger LOGGER = LoggerFactory.getLogger(AdSendSMSController.class);

    @Autowired
    private ILoginService loginService;
    @Autowired
    private IDoctorService doctorService;

    /**
     * @param phoneNum   医生输入手机号码
     * @param actionType 功能类型(1/注册；2/忘记密码；3/修改手机号；4/修改密码; 5/登录验证; 6/登录验证-2.5.0优化后)
     *
     * @return
     */
    @ApiOperation(value = "发送短信", notes = "发送验证短信", httpMethod = "POST")
    @ApiImplicitParams({@ApiImplicitParam(name = "phoneNum", value = "手机号", required = true, dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "actionType", value = "请求类型((1/注册；2/忘记密码；3/修改手机号；4/修改密码; 5/登录验证; 6/登录验证-2.5.0优化后);7/修改签名密码;)",
                    allowableValues = "1,2,3,4,5,6,7", required = true, dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "t", value = "签名时间戳", required = true, dataType = "long", paramType = "query"),
            @ApiImplicitParam(name = "sign", value = "签名", required = true, dataType = "string", paramType = "query"),})
    @RequestMapping(value = "/sendSms")
    @ResponseBody
    public void sendSMs(String phoneNum, Integer actionType, Long t, String sign) throws BusinessException {
        LOGGER.info("发送短信 请求参数：phoneNum = [{}], actionType = [{}], t = [{}], sign = [{}]", phoneNum, actionType, t, sign);

        // 1 手机号校验
        if (phoneNum == null || "".equals(phoneNum)) {
            LOGGER.info("{} 手机号为空", phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_NULL);
        }
        if (!StringUtil.isMobileNum(phoneNum)) {
            LOGGER.error("{} 不符合手机验证规则", phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ERROR);
        }
        // 2 发送类型校验
        if (actionType == null) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ACT_ERROR);
        }

        if (t == null || sign == null) {
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }

        // 签名校验
        Map<String, Object> signParams = new HashMap<>();
        signParams.put("phoneNum", phoneNum);
        signParams.put("actionType", actionType);
        signParams.put("t", t);
        boolean verify = SignatureVerifyUtil.verifySign(signParams, sign);
        if (!verify) {
            LOGGER.warn("签名校验失败signParams{}, sign:{}", signParams, sign);
            throw new BusinessException(ExceptionCodes.SIGN_ERR);
        }

        String cacheKey = "";
        // 1/注册；2/忘记密码；3/修改手机号;4/修改密码；5/登录验证；6/登录验证-2.5.0优化后
        switch (actionType) {
            case 1:
                if (this.existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.REGIST_EXSIT);
                }
                cacheKey = PropertyValueConstants.PHONE_REGIST_KEY + phoneNum;
                break;
            case 2:
                if (!this.existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.LOGIN_NOT_EXSIT);
                }
                if (this.isForbidden(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.DOCTOR_ACCOUNT_NOT_NOMAL);
                }
                cacheKey = PropertyValueConstants.PHONE_FORGET_KEY + phoneNum;
                break;
            case 3:
                if (this.existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.REGIST_EXSIT);
                }
                cacheKey = PropertyValueConstants.PHONE_MODIFY_PHONE_KEY + phoneNum;
                break;
            case 4:
                if (!this.existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.LOGIN_NOT_EXSIT);
                }
                if (this.isForbidden(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.DOCTOR_ACCOUNT_NOT_NOMAL);
                }
                cacheKey = PropertyValueConstants.PHONE_MODIFY_PWD_KEY + phoneNum;
                break;
            case 5:
                if (this.existLogin(phoneNum) && this.isForbidden(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.DOCTOR_ACCOUNT_NOT_NOMAL);
                }
                cacheKey = PropertyValueConstants.PHONE_LOGIN_PWD_KEY + phoneNum;
                break;
            //TODO 5\6都是登录验证码 ？
            case 6: // changed by chenlin 2.5.0 优化验证登录短信逻辑
                if (!this.existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.LOGIN_NOT_EXSIT);
                }
                if (this.isForbidden(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.DOCTOR_ACCOUNT_NOT_NOMAL);
                }
                cacheKey = PropertyValueConstants.PHONE_LOGIN_PWD_KEY + phoneNum;
                break;
            case 7: //
                if (!this.existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.LOGIN_NOT_EXSIT);
                }
                if (this.isForbidden(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.DOCTOR_ACCOUNT_NOT_NOMAL);
                }
                cacheKey = PropertyValueConstants.PHONE_ESIGN_PWD_KEY + phoneNum;
                break;
            default:
                LOGGER.error(" {}发送短信验证码不正确", actionType);
                throw new BusinessException(ExceptionCodes.SMS_PHONE_ACT_ERROR);
        }
        String code = null;
        // V1.4 保存每次生成的验证码有效期为10分钟，如果用户10分钟内获取，则返回同一个验证码
        // String cacheCodeKey = cacheKey + "_code";
        // if (RedisUtils.existsKey(cacheCodeKey)) {
        // code = (String) RedisUtils.get(cacheCodeKey);
        // }
        // if (code == null) {
        // code = GengerCode.generateSmsCode();
        // RedisUtils.set(cacheCodeKey, code, PropertyValueConstants.SAVE_VERIFY_CODE);
        // }
        // 每次生成的验证码有效期为10分钟，如果已使用则重新生成
        if (RedisUtils.existsKey(cacheKey)) {
            code = (String)RedisUtils.get(cacheKey);
        }
        if (code == null) {
            code = GengerCode.generateSmsCode();
        }

        if (RedisUtils.existsKey(PropertyValueConstants.PHONE_SEND_TIME_KEY + cacheKey)) {
            LOGGER.info("发送验证码两次间隔小于1分钟,电话为phoneNum=" + phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_MAX_FREQUENCY);
        }
        // 验证用户错误输入次数是否达到上限
        if (this.loginService.validUserOperatorFlag(cacheKey)) {
            LOGGER.info("发送验证码由于连续多次输入错误，账号暂时被锁定,电话为phoneNum=" + phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_VALID_MAX_COUNT);
        }
        // 验证码存放10分钟
        RedisUtils.set(cacheKey, code, PropertyValueConstants.SAVE_VERIFY_CODE);
        // 验证码发送时间间隔
        // RedisUtils.set(PropertyValueConstants.PHONE_SEND_TIME_KEY + phoneNum, "", PropertyValueConstants.SEND_SPACE);
        RedisUtils.set(PropertyValueConstants.PHONE_SEND_TIME_KEY + cacheKey, "", PropertyValueConstants.SEND_SPACE);
        // 统计当天发送量,如果发送key不存在，则删除以前统计量，否则在原统计量上激增
        if (!RedisUtils.existsKey(PropertyValueConstants.PHONE_DAY_SEND_COUNT_KEY + phoneNum)) {
            RedisUtils.delete(PropertyValueConstants.PHONE_SEND_COUNT_KEY + phoneNum);
            RedisUtils.set(PropertyValueConstants.PHONE_DAY_SEND_COUNT_KEY + phoneNum, "", DateUtil.getDayOfSecond());
        }
        // 验证码发送总次数统计
        long count = RedisUtils.incre(PropertyValueConstants.PHONE_SEND_COUNT_KEY + phoneNum);
        if (count > PropertyValueConstants.SEND_MAX_COUNT) {
            LOGGER.info("当天发送验证码次数已经超过10次，电话为phoneNum=" + phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_MAX_COUNT);
        }

        // 调用远程接口，发送验证码
        Template tmpl = SMSUtil.Template.PWD;
        SMSUtil.sendSMS(phoneNum, tmpl, code);
    }

    private boolean existLogin(String phoneNum) {
        // 读库获取
        return this.loginService.findCountByPhoneNum(phoneNum);
    }

    private boolean isForbidden(String phoneNum) {
        // 医生是否被禁用
        Doctor doctor = null;
        doctor = this.doctorService.getDoctorByPhone(phoneNum);
        return doctor != null && doctor.getAccountStatus() != null && doctor.getAccountStatus() != 0;
    }
}
